package controller.editorcontroller;

import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import model.LogicType;
import view.UtilityLogicDesigns;
import view.commonview.LogicViewElement;
import view.editorview.EditorArea;
import model.editormodel.EditorModel;
import model.editormodel.Input;
import model.editormodel.Output;
import model.editormodel.LogicEditorElement;
import view.commonview.InfoArea;

public class AutoCreateSwitchListener implements ActionListener {

	private EditorModel eModel;
	private EditorArea eArea;
	private InfoArea infoArea;

	public AutoCreateSwitchListener(EditorModel eModel, EditorArea eArea, InfoArea infoArea) {
		this.eModel = eModel;
		this.eArea = eArea;
		this.infoArea = infoArea;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		createSwitches();
	}

	/**
	 * Ueberprueft ob ein Schalter an einer bestimmten Position eingefuegt
	 * werden koennte
	 * 
	 * @param xPos
	 *            xKoordinate in Pixel
	 * @param yPos
	 *            yKoordinate in Pixel
	 * @return
	 */
	private boolean isPossibleSwitchLocation(double xPos, double yPos) {
		Shape shape = UtilityLogicDesigns.getLogicDesign(LogicType.SWITCH,
				xPos, yPos);
		for (LogicViewElement lVE : eArea.getLogicViewElements()) {
			if (eArea.shapesIntersect(shape, lVE.getDesign())) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Durchlaueft alle unverbundenen Eingaenge der Schaltung und erzeugt fuer
	 * jeden einen Schalter und verbindet diese mit dem Eingang
	 */
	private void createSwitches() {
		boolean gotAfail = false;
		for (Input inp : eModel.getUnrelatedInputs()) {
			gotAfail = gotAfail || !findLocationForSwitch(inp);
		}
		if (gotAfail) {
			infoArea.addInfoText("Konnte keine passende Position zum einfuegen der Schalter finden");
		}
	}

	/**
	 * Methode die eine geeignete Position fuer den neuen Schalter sucht
	 * @param inp Input mit dem verbunden werden soll
	 * @return true, wenn eine Position gefunden werden konnte, false sonst
	 */
	private boolean findLocationForSwitch(Input inp) {
		LogicEditorElement elemOfInput = inp.getMySuperElement();
		double tryX = Math.max(0, elemOfInput.getXCoord() - 100);
		double tryY = Math.max(0, elemOfInput.getYCoord() + inp.getYRelToElement() - 7); //-7 dass die linie schoen grade verlaueft

		//geht positionen so durch, dass erst versucht wird den schalter links
		//vom bauteil zu positionieren... falls man irgendwann an den rand kommt
		//wird versucht nach oben zu gehen... falls man da auch an den rand kommt
		//wird es rechts vom bauteil versucht... falls dann rand wird nach unten gegangen
		//NOCH OPTIMIERUNGSFAEHIG!!
		while (!isPossibleSwitchLocation(tryX, tryY)) {
			if (tryX > 0) {
				tryX = Math.max(0, tryX - 50);
			} else {
				tryY = Math.max(0, tryY - 50);
			}
			if (tryX == 0 && tryY == 0) {
				tryY = elemOfInput.getYCoord() + inp.getYRelToElement() - 7;
				while (!isPossibleSwitchLocation(tryX, tryY)) {
					if (tryX < eArea.getWidth()) {
						tryX = Math.min(eArea.getWidth(), tryX + 50);
					} else {
						tryY = Math.min(eArea.getHeight(), tryY + 50);
					}
					if (tryX == eArea.getWidth() && tryY == eArea.getHeight()) {
						return false;
					}
				}
			}
		}
		LogicEditorElement newSwitch = eModel.addLogicElement(LogicType.SWITCH,
				null, tryX, tryY);
		eModel.setConnection(newSwitch.getOutputs().get(Output.STD_O), inp);
		return true;
	}

}
